const app = getApp()
var utils = require('.././util.js');
// var cryptoService = require('../bleFile/cryptoService.js'); //引入加密文件
// var crc = require('../bleFile/crc.js'); //引入crc校验


var serviceUUID = [] //主 service 的 uuid 列表
var writeUUID = ""; //写读 UUID
var notifyUUID = ""; //notify UUID
var delayUUID = ""; //护眼仪控制时长UUID
var filterServiceUUID = ""; //过滤获取到的服务uuid(有些会返回多条数据)
var filterDeviceName = ""; //设备名称

var macAddress = ""; //保存得到mac地址
var flagFromTypes = ''; //来源类型(根据不同产品执行蓝牙协议)  例：1-->充电宝 2-->售卖机....
var _discoveryStarted = false;
var deviceId = ''; //用于区分设备的 id

var _deviceId = '';
var _serviceId = '';
var _characteristicId = '';
var status = false; //当前状态
var action_type = ''; //操作类型
var code = -1;
var isnotExist = true //防止多次执行

var asddCallBack = null; //接收数据处理
var asddErrorCallback = null; //接收错误码处理
var asddWriteErrors = null; //接收写入错误处理

var tempStr = ''; //拼接设备返回数据
var rssiVal = ''; //RSSI值
var currentSerialVal = ''; //当前点击格子柜序号


//当前操作类型
var OptionEnum = {
    None: -1,
    Connection: 0, //连接
    Reconnection: 1, //重连
    CloseLock: 2, //关闭
    VendingOpenLock: 8, //打开售卖机
    ReadStatus: 9, //读售卖机状态
    ReadBattery: 10, //读售卖机电量
};
//这个是变量, 存储数据的变量
var action_type = OptionEnum.None;



function inArray(arr, key, val) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i][key] === val) {
            return i;
        }
    }
    return -1;
}

// ArrayBuffer转16进度字符串示例
function ab2hex(buffer) {
    var hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
            return ('00' + bit.toString(16)).slice(-2)
        }
    )
    return hexArr.join('');
}

/**
 * 去掉 冒号
 */
function clearSymbol(str) {
    str = str.replace(/:/g, ""); //取消字符串中出现的所有冒号
    return str;
}

/**
 *  匹配规则: 取名称后面的mac
 */
function getNameMac(macAddress, len, name) {
    let clearColonMac = clearSymbol(macAddress);
    let lastFourMac = clearColonMac.substring(clearColonMac.length - len);
    let strName = name.toUpperCase();
    strName = strName + lastFourMac.toUpperCase(); //转大写
    console.log('拼接后的' + strName);
    return strName
}


/**
 * 区分不同类型的服务相关uuid
 * 1-->充电宝 2-->售卖机
 */
function flagServiceIDFun(serviceType) {
    console.log('方法中拿到type======>', serviceType);
    if (serviceType == 1) {
        serviceUUID[0] = "0000*E0-00*0-*0*0-*0*0-00**5F9**4*B"; //主 service的uuid 列表
        writeUUID = "00*0**E2-00*0-*0*0-*0*0-00**5F9**4*B"; //写读 UUID
        notifyUUID = "00*0**E1-00*0-*0*0-*0*0-00**5F9**4*B"; //notify UUID
        filterServiceUUID = "*E0";
    } else if (serviceType == 2) {
        serviceUUID[0] = "0000*E0-00*0-*0*0-*0*0-00**5F9**4*B"; //主 service的uuid 列表
        writeUUID = "00*0**E2-00*0-*0*0-*0*0-00**5F9**4*B"; //写读 UUID
        notifyUUID = "00*0**E1-00*0-*0*0-*0*0-00**5F9**4*B"; //notify UUID
        filterServiceUUID = "*E0";

        //这里介绍用name匹配方法
        filterDeviceName = getNameMac(macAddress, 6, 'abc_'); //设备名称
    }
}


/**
* 初始化蓝牙模块
* 参数1： mac地址
* 参数2： 当前操作类型
* 参数3： 当前点击格子的序号（第几个格子）
*/
function initBle(fromMac, flagTypes, currentSerial) {
    tempStr = ''; //清空

    //断开连接【每次初始化先断开连接】
    closeBLEConnection();

    console.log("你获取到mac地址了么....", fromMac + '获取到类型为====》' + flagTypes);
    // macAddress = clearSymbol(fromMac);
    macAddress = fromMac; //保存mac
    flagFromTypes = flagTypes //类型来源

    //获取RSSI值
    let getRssi = wx.getStorageSync('rssi');
    rssiVal = getRssi;

    //调用主服务id相关
    flagServiceIDFun(flagTypes);

    // 获取当前点击售卖机序号值
    currentSerialVal = currentSerial


    _discoveryStarted = false;

    //初始化蓝牙模块
    wx.openBluetoothAdapter({
        success: (res) => {
            console.log('openBluetoothAdapter 初始化蓝牙模块是否成功:', res)
            // 监听寻找新设备事件
            onBluetoothDeviceFound();

            //开始搜寻附近的蓝牙外围设备
            startBluetoothDevicesDiscovery();
        },
        fail: (res) => {
            console.log('初始化蓝牙失败', res);
            asddErrorCallback(res.errCode, "");

            //监听蓝牙适配器状态变化事件【根据需求是否执行】
            // wx.onBluetoothAdapterStateChange(function (res) {
            //     console.log('蓝牙适配器状态更改结果:  ', res)
            //     if (res.available) {
            //         console.log('蓝牙可用，搜索设备:--》 ')
            //         onBluetoothDeviceFound();
            //         startBluetoothDevicesDiscovery();
            //     }
            // })
        }
    })
}


/**
 * 监听寻找新设备事件
 * 注意咯： 这里有展示三种不同方式来连接设备，请看备注【mac, name, 根据系统的】 各取所需吧。
 */
function onBluetoothDeviceFound() {
    wx.onBluetoothDeviceFound((res) => {
        console.log('广播数据结果:', res);

        res.devices.forEach(device => {
            if (!device.name && !device.localName) {
                return
            }

            // 转换后, 根据协议文档取需要数据 （advertisData不一定有数据）
            if (device.advertisData != null) { //判断对象是否为null，advertisData不一定有
                var hexStr = ab2hex(device.advertisData);
                console.log("广播数据中转换后：advertisData---->" + hexStr);
            }


            // 充电宝 android用mac， ios用name匹配
            if (flagFromTypes == 1) {
                if (app.getPlatform() == 'android') {
                    if ((macAddress != "") && (macAddress == device.deviceId) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;

                        stopBluetoothDevicesDiscovery();
                        //连接设备
                        createBLEConnection();
                    }
                } else if (app.getPlatform() == 'ios') {
                    let deviceName = device.name.toUpperCase();
                    if ((deviceName.indexOf(filterDeviceName) != -1) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;

                        //停止搜寻附近的蓝牙外围设备
                        stopBluetoothDevicesDiscovery();
                        //连接设备
                        createBLEConnection();
                    }
                }
            } else if (flagFromTypes == 2) {
                // 格子柜 Android IOS通过名称匹配
                if (parseFloat(device.RSSI) > parseFloat(rssiVal)) {
                    let deviceName = device.name.toUpperCase();
                    if ((deviceName.indexOf(filterDeviceName) != -1) && isnotExist) {
                        isnotExist = false;
                        deviceId = device.deviceId;

                        //停止搜寻附近的蓝牙外围设备
                        stopBluetoothDevicesDiscovery();
                        //连接设备
                        createBLEConnection();
                    }
                }
            }
        })
    })
}



/**
 * 执行连接蓝牙设备
 */
function startBluetoothDevicesDiscovery() {
    if (_discoveryStarted) {
        return;
    }
    _discoveryStarted = true

    wx.startBluetoothDevicesDiscovery({
        services: serviceUUID,
        allowDuplicatesKey: false,
        success: (res) => {
            console.log('启动搜索蓝牙设备, 结果  :', res)
            //onBluetoothDeviceFound()  //先调用此方法再使用startBluetoothDevicesDiscovery
        },
        fail(res) {
            asddErrorCallback(res.errCode, "");
            console.log('startBluetoothDevicesDiscovery fail', res);
        }
    })
}


//停止搜寻附近的蓝牙外围设备。
function stopBluetoothDevicesDiscovery() {
    wx.stopBluetoothDevicesDiscovery()
}


/**
 * 连接蓝牙设备
 */
function createBLEConnection() {
    var that = this;
    wx.createBLEConnection({
        deviceId: deviceId,
        success: (res) => {
            wx.showToast({
                title: '设备连接成功',
                duration: 2000
            })
            //获取蓝牙所有服务
            getBLEDeviceServices(deviceId)
        },
        fail: (res) => {
            console.log('createBLEConnection fail', res);
            asddErrorCallback(res.errCode, "");
        }
    })
    stopBluetoothDevicesDiscovery(); //停止搜索
}


/**
 * 断开蓝牙连接
 */
function closeBLEConnection() {
    //停止搜索
    stopBluetoothDevicesDiscovery();

    tempStr = ''; //清空

    if (deviceId) {
        wx.closeBLEConnection({
            deviceId: deviceId,
            success: function (res) {
                console.log("closeBLEConnection。success", res);

            },
            fail: function (res) {
                console.log("closeBLEConnection。fail", res);
            },
            complete: function () {
                status = false;
            }
        })

        wx.closeBluetoothAdapter({
            success: function (res) {
                console.log("closeBluetoothAdapter ==>res:", res);
            },
            fail: function (error) {
                console.log("closeBluetoothAdapter ==>error:", error);
            }
        })
    }

    _discoveryStarted = false;
    isnotExist = true;
    _deviceId = '';
    deviceId = '';
}


/**
 * 获取蓝牙所有服务
 */
function getBLEDeviceServices(deviceId) {
    wx.onBLEConnectionStateChange(function (res) {
        console.log("onBLEConnectionStateChange:", res);
        // 该方法回调中可以用于处理连接意外断开等异常情况
        console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
        if (res.connected == false) {
            console.log("连接意外断开等****", _deviceId);
            _deviceId = '';
            if (flagFromTypes == 1 && flagFromTypes == 2) {
                asddErrorCallback(1010, ""); //?
            }
        }
    });

    wx.getBLEDeviceServices({
        deviceId: deviceId,
        success: (res) => {
            // console.log("获取蓝牙设备所有服务(service)", res);
            for (let i = 0; i < res.services.length; i++) {
                let tmpUuid = res.services[i].uuid;
                if ((res.services[i].isPrimary) && (tmpUuid.indexOf(filterServiceUUID) != -1)) {
                    getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
                    return
                }
            }
        },
        fail: (res) => {
            console.log('getBLEDeviceServices fail', res);
            asddErrorCallback(res.errCode, "");
        }
    })
}


/**
 * 获取蓝牙特征值
 */
function getBLEDeviceCharacteristics(deviceId, serviceId) {
    wx.getBLEDeviceCharacteristics({
        deviceId: deviceId,
        serviceId: serviceId,
        success: (res) => {
            // console.log('蓝牙设备特征值信息:', res);
            for (let i = 0; i < res.characteristics.length; i++) {
                let item = res.characteristics[i]
                var itemUUID = item.uuid.toUpperCase(); //转大写

                if (item.properties.read && itemUUID == writeUUID) {
                    wx.readBLECharacteristicValue({
                        deviceId: deviceId,
                        serviceId: serviceId,
                        characteristicId: item.uuid,
                    })
                }
                if (item.properties.write && itemUUID == writeUUID) {
                    _deviceId = deviceId
                    _serviceId = serviceId
                    _characteristicId = item.uuid

                    //发送指令【说明：如需连接设备后发相关指令可以在这里调用】
                    if (flagFromTypes == 1) { //充电宝
                        powerBank.send(); //充电开机指令
                    } else if (flagFromTypes == 2) { //售卖机
                        vendingObj.checkEnKey(); //AES校验
                    }
                }

                if (notifyUUID == itemUUID) {
                    if (item.properties.notify || item.properties.indicate) {
                        console.log('调用notifyBLECharacteristicValueChange前', item.uuid);
                        wx.notifyBLECharacteristicValueChange({
                            deviceId: deviceId,
                            serviceId: serviceId,
                            characteristicId: item.uuid,
                            state: true,
                            success(res) {
                                console.log('notification通知数据', res);
                                status = true;
                                // wx.hideLoading();
                            },
                            fail(res) {
                                console.log('notifyBLECharacteristicValueChange fali', res);
                            }
                        })
                    }
                }
            }
        },
        fail: (res) => {
            console.log('getBLEDeviceCharacteristics fail', res)
            asddErrorCallback(res.errCode, "");
        }
    })


    // 操作之前先监听，保证第一时间获取数据
    wx.onBLECharacteristicValueChange(function (res) {
        console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`)
        console.log("操作类型:" + action_type);

        var resData = ab2hex(res.value);
        console.log("设备返回数据--->", resData); //5d0000000001be304d

        // 判断不同类型处理数据
        if (flagFromTypes == 2) {
            console.log('开始调用 自动售卖机====> 处理返回的数据');
            vendingObj.handleResData(resData); //处理返回数据
        }
    })
}

/**
 * 写入数据
 */
function writeData(hex, action = '') {
    if (!status) {
        return;
    }

    if (!_deviceId) {
        asddWriteErrors('w');
        return;
    }

    setTimeout(() => {
        //这里使用`TypedArray视图`中`Uint8Array（无符号 8 位整数）`操作
        var enDataBuf = new Uint8Array(hex);
        var buffer1 = enDataBuf.buffer

        wx.writeBLECharacteristicValue({
            deviceId: _deviceId,
            serviceId: _serviceId,
            characteristicId: _characteristicId,
            value: buffer1,
            success: (res) => {
                wx.hideLoading();
                console.log("写数据返回结果", res.errMsg);
            },
            fail(res) {
                console.log("写数据失败..", res);
                asddErrorCallback(res.errCode, "");
            }
        })
    }, 1000)
}


/**
 * 售卖机
 */
var vendingObj = {
    /**
     * 校验AES密钥
     * 字符、key文档有说明
     */
    checkEnKey: function () {
        status = true;
        var strKey = [0xd0, 0xf0, 0xf0, 0x80, 0x50, 0xa0, 0x60, 0x10, 0x20, 0x50, 0xc0, 0xd0, 0x80, 0x80, 0x40, 0x90];
        var key = [0xd0, 0xf0, 0xf0, 0x80, 0x50, 0xa0, 0x60, 0x10, 0x20, 0x50, 0xc0, 0xd0, 0x80, 0x80, 0x40, 0x90];
        var cryptoKey = new Uint8Array(key);
        enKEY = cryptoKey;
        //得出加密后的指令, 十六进制的数据
        var enHEX = cryptoService.updateEncrypt(strKey, enKEY);
        writeData(enHEX);
    },

    /**
     * 查询设备信息
     */
    queryDeviceInfo: function () {
        action_type = OptionEnum.ReadBattery; //改变操作类型
        let hex = [0x69, 0xf2, 0x00, 0x89];
        writeData(hex); //写入数据
    },

    /**
    * 开锁指令
    */
    openVendingLock: function (callBack) {
        status = true;
        action_type = OptionEnum.VendingOpenLock;
        asddCallBack = callBack;
        //获取当前开锁的编号及转换
        let getCurrentVal = Number(currentSerialVal);
        getCurrentVal = getCurrentVal.toString(16);
        // let tempVal = '0x0' + getCurrentVal;
        let tempVal = parseInt(getCurrentVal, 16);
        console.log('====开锁编号===》', tempVal);
        let hex = [0xfe, 0x4e, 0x30, 0x46, 0x4a, 0x00, tempVal, 0x00, 0x00, 0x3e];
        writeData(hex);
    },

    /**
     * 处理格子机查询信息电量回调
     * 目的：获取到相关数据，发送给后端（查看设备电量）
     */
    readBatteryCallBack: function (battery) {
        console.log("=======>>>电量:", battery);
        action_type = OptionEnum.None;

        //这里获取到电量, 返回给index.js页面
        if (asddCallBack != null) {
            asddCallBack(battery, OptionEnum.ReadBattery);
        } else {
            console.log("是否为空=======标签 2");
        }
    },


    /**
     * 处理开锁成功回调
     */
    openLockCallback: function (resData) {
        var isOpenLock = false;
        // 根据当前点击的柜子序号，截取对应的数据状态
        var star = Number(currentSerialVal) * 2
        var subSerial = resData.substring(star, star + 2);
        if (subSerial.toUpperCase() == 'F0') {
            isOpenLock = true;
        }
        console.log("=======>>>开锁:", isOpenLock ? "成功" : "失败");
        action_type = OptionEnum.None;

        if (asddCallBack != null) {
            asddCallBack(isOpenLock, OptionEnum.VendingOpenLock);
        } else {
            console.log("是否为空=======标签 3");
        }
    },


    /**
     * 处理返回数据
     * 例如： 00f05d09000001be304d
     */
    handleResData: function (resData) {
        let checkStatus = resData.substring(2, 4);

        if (checkStatus.toUpperCase() == 'F0' && action_type == OptionEnum.Connection) { //校验状态
            vendingObj.queryDeviceInfo(); //查询设备信息

        } else if (action_type == OptionEnum.ReadBattery) { //操作的是获取设备电量

            let batteryVal = resData.substring(6, 8);
            batteryVal = parseInt(batteryVal, 16);
            vendingObj.readBatteryCallBack(batteryVal);

        } else if (action_type == OptionEnum.VendingOpenLock) { //操作的是 开锁

            vendingObj.openLockCallback(resData);
        }
    }
}


//设置连接
function setConnectionActionType(callBack) {
    action_type = OptionEnum.Connection;
    asddCallBack = callBack;
}

//设置重连
function setReconnectionActionType() {
    action_type = OptionEnum.Reconnection;
}

// 设置错误
function setAsddErrorCallback(callBack) {
    asddErrorCallback = callBack;
}

//设置关闭
function setCloseActionType(callBack) {
    action_type = OptionEnum.CloseLock;
    asddCallBack = callBack;
}

//设置写入错误
function setWriteError(callBack) {
    asddWriteErrors = callBack;
}

//清除
function clearCallBack() {
    asddCallBack = null;
}

/**
 * 清空loadding
 */
function hideLoading() {
    wx.hideLoading();
}

/**
 * 检查是否打开蓝牙
 * 未连接设备前检测
 */
function checkIsOpenBluetooth(isEXec) {
    wx.openBluetoothAdapter({
        success: (res) => {
            // console.log('openBluetoothAdapter 初始化蓝牙模块是否成功:', res);
            isEXec(true);
        },
        fail: (res) => {
            // console.log('初始化蓝牙失败', res);
            wx.showModal({
                title: '提示',
                content: '请检查手机蓝牙是否打开',
                showCancel: false
            })

            isEXec(false);
        }
    })
}


/**
 * 蓝牙连接过程中错误码
 * 10000 / 10006
 */
function bluetoothStatus(errorType) {
    switch (errorType) {
        case 10001:
            wx.showModal({
                title: '提示',
                content: '请检查手机蓝牙是否打开',
                showCancel: false
            })
            break;
        case 10002:
            wx.showToast({
                title: '没有找到指定设备',
                icon: 'none'
            })
            break;
        case 10003:
            wx.showToast({
                title: '连接失败',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10004:
            wx.showToast({
                title: '没有找到指定服务',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10005:
            wx.showToast({
                title: '没有找到指定特征值',
                icon: 'none'
            })
            closeBLEConnection();
            break;
        case 10007:
        case 10008:
        case 10013:
            wx.showToast({
                title: '设备启动失败，请重试',
                icon: 'none'
            })
            break;
        case 10009:
            wx.showModal({
                title: '提示',
                content: '当前系统版本过低，请更新版本体验',
                showCancel: false
            })
            break;
        case 10012:
            wx.showToast({
                title: '连接超时',
                icon: 'none'
            })
            break;
    }
}


module.exports = {
    initBle: initBle,
    clearCallBack: clearCallBack,
    closeBLEConnection: closeBLEConnection,
    setConnectionActionType: setConnectionActionType,
    setReconnectionActionType: setReconnectionActionType,
    setAsddErrorCallback: setAsddErrorCallback,
    setCloseActionType: setCloseActionType,
    setWriteError: setWriteError,
    checkIsOpenBluetooth: checkIsOpenBluetooth,
    bluetoothStatus: bluetoothStatus,
    openVendingLock: vendingObj.openVendingLock,
}